
package decoderstage

import memandwritebackstage.MemExtOpCode._
import executestage.ALUOpCode._
import chisel3._
import chisel3.util._
import decoderstage.EXTOpCode._
import decoderstage.NPCOpCode._
class StallInfo extends Bundle{
  val T = UInt(3.W)
  val grfWriteBus = new GRFWriteBus
//  val thisStall = Bool()//该流水级Stall
}

class Decoder extends Module {
  val io = IO(new Bundle {
    val mipsInstr = Input(UInt(32.W))
    val grfReadBus = Output(new GRFReadBus)
    val rd = Output(UInt(5.W))
    val imm16 = Output(UInt(16.W))
    val imm26 = Output(UInt(26.W))
    val stallInfo = Output(new StallInfo)
    val stall = Output(Bool())
    val D_stallInfo = Input(new StallInfo)
    val E_stallInfo = Input(new StallInfo)
    val NPC_OpCode = Output(UInt(NPC_Width.W))
    val ALU_OpCode = Output(UInt(ALU_Width.W))
    val ALU_isReg = Output(Bool())
    val EXT_OpCode = Output(UInt(EXT_Width.W))
    val MEM_WriteEnable = Output(UInt(4.W))//在E级还需要偏转
    val MEM_ExtOpCode = Output(UInt(MEXT_Width.W))
  })
  val mipsInstr = io.mipsInstr
  val rs = mipsInstr(25,21)
  val rt = mipsInstr(20,16)
  val rd = mipsInstr(15,11)
  io.grfReadBus.rs := rs
  io.grfReadBus.rt := rt
  io.rd := rd
  io.imm16 := mipsInstr(15,0)
  io.imm26 := mipsInstr(25,0)

  val stallInfo = io.stallInfo
  val funct = io.mipsInstr(5,0)
  val opCode = io.mipsInstr(31,26)

  val lb = opCode === "h20".U
  val lbu = opCode === "h24".U
  val lh = opCode === "h21".U
  val lhu = opCode === "h25".U
  val lw = opCode === "h23".U
  val sb = opCode === "h28".U
  val sh = opCode === "h29".U
  val sw = opCode === "h2b".U

  val addi = opCode === "h8".U
  val addiu = opCode === "h9".U
  val add = opCode === "h0".U && funct === "h20".U
  val addu = opCode === "h0".U && funct === "h21".U
  val sub = opCode === "h0".U && funct === "h22".U
  val subu = opCode === "h0".U && funct === "h23".U
  val lui = opCode === "hf".U

  val ori = opCode === "hd".U
  val and = opCode === "h0".U && funct === "h24".U
  val or = opCode === "h0".U && funct === "h25".U
  val xor = opCode === "h0".U && funct === "h26".U
  val nor = opCode === "h0".U && funct === "h27".U
  val andi = opCode === "hc".U
  val xori = opCode === "he".U

  val beq = opCode === "h4".U
  val bne = opCode === "h5".U
  val blez = opCode === "h6".U
  val bgtz = opCode === "h7".U
  val bltz = opCode === "h1".U && io.mipsInstr(20,16) === "h0".U
  val bgez = opCode === "h1".U && io.mipsInstr(20,16) === "h1".U
  val j = opCode === "h2".U
  val jal = opCode === "h3".U
  val jr = opCode === "h0".U && funct === "h8".U
  val jalr = opCode === "h0".U && funct === "h9".U
  val nop = io.mipsInstr === "h0".U

  val mult = opCode === "h0".U && funct === "h18".U
  val multu = opCode === "h0".U && funct === "h19".U
  val div = opCode === "h0".U && funct === "h1a".U
  val divu = opCode === "h0".U && funct === "h1b".U
  val mfhi = opCode === "h0".U && funct === "h10".U
  val mthi = opCode === "h0".U && funct === "h11".U
  val mflo = opCode === "h0".U && funct === "h12".U
  val mtlo = opCode === "h0".U && funct === "h13".U

  val sll = opCode === "h0".U && funct === "h0".U
  val srl = opCode === "h0".U && funct === "h2".U
  val sra = opCode === "h0".U && funct === "h3".U
  val sllv = opCode === "h0".U && funct === "h4".U
  val srlv = opCode === "h0".U && funct === "h6".U
  val srav = opCode === "h0".U && funct === "h7".U

  val slt = opCode === "h0".U && funct === "h2a".U
  val slti = opCode === "ha".U
  val sltu = opCode === "h0".U && funct === "h2b".U
  val sltiu = opCode === "hb".U

  val mfc0 = opCode === "b010000".U && io.mipsInstr(25,21) === "b00000".U
  val mtc0 = opCode === "b010000".U && io.mipsInstr(25,21) === "b00100".U
  val eret = io.mipsInstr === "h42000018".U

  // stall ctrl unit
  stallInfo.T := MuxCase(3.U,Seq(
    (lw||lhu||lh||lbu||lb||mfc0) -> 3.U,
    (addi||addiu||add||addu||sub||subu||lui||jal||jalr||
      mfhi||mflo||sll||srl||sra||sllv||srlv||srav||
      and||or||xor||nor||ori||andi||xori||slt||sltu||slti||sltiu) ->2.U
  ))

  val grfWriteBus = stallInfo.grfWriteBus
  grfWriteBus.writeData := DontCare//此时不可能产生有效的结果
  grfWriteBus.writeEnable := !nop && (addi||addiu||add||addu||sub||subu||
    ori||lui||or||and||xor||nor||andi||xori||
    lw||lh||lhu||lb||lbu||
    jal||jalr||
    mfhi||mflo||
    sll||srl||sra||sllv||srlv||srav||
    slt||slti||sltu||sltiu||
    mfc0||
    mfhi||mflo)
  grfWriteBus.writeID := MuxCase(io.rd,Seq(
    (addi||addiu||ori||xori||andi||lui||lw||lhu||lh||lbu||lb||slti||sltiu||mfc0) -> rt,
    (add||addu||sub||subu||mfhi||mflo||sll||srl||sra||sllv||srlv||srav||slt||sltu||
      and||or||xor||nor||jalr) -> rd,
    (jal) -> 31.U
  ))
  val needRs = rs =/= 0.U && (addi||addiu||add||addu||sub||subu||lw||sw||lb||lbu||lh||lhu||sb||sh||jr||jalr||mult||multu||div||divu||mthi||mtlo||
    sllv||srlv||srav||and||or||xor||nor||ori||andi||xori||slt||sltu||slti||sltiu||
    beq||bne||blez||bgtz||bltz||bgez)
  val needRt = rt =/= 0.U && (add||addu||sub||subu||sw||sb||sh||mult||multu||div||divu||sll||srl||sra||sllv||srlv||srav||
    and||or||xor||nor||slt||sltu||beq||bne||mtc0)
  val T_Rs = WireInit(stallInfo.T)
  val T_Rt = WireInit(stallInfo.T)//确保位宽一致

  T_Rs := MuxCase(0.U,Seq(
    (beq||bne||blez||bgtz||bltz||bgez) -> 0.U,
      (addi||addiu||add||addu||sub||subu||lw||sw||lb||lbu||lh||lhu||sb||sh||mult||multu||div||mthi||mtlo||
        divu||sllv||srlv||srav||and||or||xor||nor||ori||andi||xori||slt||sltu||slti||sltiu) -> 1.U
  ))
  T_Rt := MuxCase(0.U,Seq(
    (beq||bne) -> 0.U,
    (add||addu||sub||subu||mult||multu||div||divu||sll||srl||sra||sllv||srlv||srav||
      and||or||xor||nor||slt||sltu) -> 1.U,
    (sw||sb||sh||mtc0) -> 2.U
  ))
  val D_stallInfo = io.D_stallInfo
  val D_grfWriteBus = D_stallInfo.grfWriteBus
  val E_stallInfo = io.E_stallInfo
  val E_grfWriteBus = E_stallInfo.grfWriteBus
  val stall_Rs = needRs  && (
    (D_grfWriteBus.writeEnable && D_stallInfo.T > T_Rs && D_grfWriteBus.writeID === rs) ||
    (E_grfWriteBus.writeEnable && E_stallInfo.T > T_Rs && E_grfWriteBus.writeID === rs))
  val stall_Rt = needRt  && (
    (D_grfWriteBus.writeEnable && D_stallInfo.T > T_Rs && D_grfWriteBus.writeID === rt) ||
    (E_grfWriteBus.writeEnable && E_stallInfo.T > T_Rs && E_grfWriteBus.writeID === rt))

  io.stall := stall_Rs || stall_Rt
  io.NPC_OpCode := MuxCase(NPC_PC4,Seq(
    j -> NPC_J,
    jal -> NPC_JAL,
    jr -> NPC_JR,
    jalr -> NPC_JALR,
    bne -> NPC_BNE,
    beq -> NPC_BEQ,
    bgez -> NPC_BGEZ,
    bgtz -> NPC_BGTZ,
    blez -> NPC_BLEZ,
    bltz -> NPC_BLTZ
  ))
  io.ALU_OpCode := MuxCase(0.U,Seq(
    (addu||addiu) -> ALU_ADDU,
    (subu) -> ALU_SUBU,
    (add||addi||lw||sw||lb||lbu||sb||lh||lhu||sh) -> ALU_ADD,
    (sub) -> ALU_SUB,
    (or|ori) -> ALU_OR,
    (and|andi) -> ALU_AND,
    (xor|xori) -> ALU_XOR,
    (nor) -> ALU_NOR,
    (lui) -> ALU_IMM,
    (sll|sllv) -> ALU_SLL,
    (srl|srlv) -> ALU_SRL,
    (sra|srav) -> ALU_SRA,
    (slt|slti) -> ALU_SLT,
    (sltu|sltiu) -> ALU_SLTU,
    (jal|jalr) -> ALU_Link
  ))
  io.ALU_isReg := (addu|add|subu|sub|or|and|xor|nor|sllv|srlv|srav|slt|sltu)

  io.EXT_OpCode := MuxCase(EXT_Sign,Seq(
    (ori|xori|andi) -> EXT_Zero,
    (lui) -> EXT_Lui,
    (sll|srl|sra) -> EXT_Shamt
  ))

  io.MEM_ExtOpCode := MuxCase(MEXT_lw,Seq(
    lb -> MEXT_lb,
    lbu -> MEXT_lbu,
    lh -> MEXT_lh,
    lhu -> MEXT_lbu
  ))
  io.MEM_WriteEnable := MuxCase(0.U(4.W),Seq(
    sw -> "b1111".U(4.W),
    sh -> "b0011".U(4.W),
    sb -> "b0001".U(4.W)
  ))
}
